home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / progutil / stdwin.zoo / test / klok.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-10-19  |  16.5 KB  |  877 lines

  1. /* Analog clock with alarm.
  2.    
  3.    Displays the date at the top, a circular clock in the middle,
  4.    and the alarm time at the bottom of the window.
  5.    The clock has two hands.
  6.    
  7.    Resizing the window recomputes the items' positions and sizes.
  8.    
  9.    When the alarm goes off, the clock window is made current,
  10.    the clock face is inverted for 5 minutes, and a beep is emitted
  11.    each minute.  The alarm can be acknowledged explicitly, which
  12.    silences it until the next time the alarm goes off.
  13.    
  14.    Dragging the hands of the clock can be used to set the time
  15.    (and the date, if you care to drag around several times).
  16.    The alarm is currently set through a dialog only.
  17.  
  18.    TO DO:
  19.        - make the display prettier (how??? everything I design gets ugly :-( )
  20.     - display alarm time as tick mark?
  21.     - improve the alarm setting procedure
  22.     - add more general 'nag' and 'calendar'-like facilities
  23.     - add a button to allow/disallow setting the time
  24.     - add a way to change the date directly
  25.     - turn it into a subroutine package like VT or editwin
  26.     - organize the code top-down instead of bottom-up
  27. */
  28.  
  29. #include "tools.h"
  30. #include "stdwin.h"
  31.  
  32. #include <math.h>
  33. #ifdef atarist
  34. #include <time.h>
  35. #else
  36. #include <sys/time.h>
  37. #endif
  38.  
  39. #ifndef PI
  40. #define PI 3.1415962        /* ... */
  41. #endif
  42.  
  43. #define ALARMTIME    5    /* Alarm goes for this many minutes */
  44.  
  45. #define LITPERC        60    /* Little hand size (percent of radius) */
  46. #define BIGPERC        80    /* Big hand size */
  47. #define SECPERC        100    /* Seconds hand size */
  48.  
  49. #define SETALARM    0
  50. #define CLEARALARM    1
  51. #define OKALARM        2
  52. #define SECONDSHAND    4
  53. #define QUIT        6
  54.  
  55. /* Global variables */
  56. char *progname= "klok";        /* Program name (for error messages) */
  57. WINDOW *win;            /* Clock window */
  58. MENU *mp;            /* Menu pointer */
  59. int centh, centv;        /* Clock center */
  60. int radius;            /* Clock radius */
  61. struct tm curtime;        /* Current time/date */
  62. int alarm= 11*60 + 42;        /* Alarm time (hh*60 + mm); -1 if off */
  63. bool alarmed;            /* Is it alarm time? */
  64. bool okayed;            /* Has the current alarm been OK'ed? */
  65. bool excited;            /* == (alarmed && !okayed) */
  66. bool do_seconds;        /* Set if drawing 'seconds' hand */
  67.  
  68. /* Force a redraw of the entire window */
  69.  
  70. changeall()
  71. {
  72.     wchange(win, 0, 0, 10000, 10000);
  73. }
  74.  
  75. /* Compute the sine of an angle given in clock units
  76.    (zero at 12 o'clock, full circle is 60).
  77.    We cache the sine values in a table,
  78.    since calling sin is too slow on some systems. */
  79.  
  80. double
  81. sine(i)
  82.     int i;
  83. {
  84.     static double sines[15+1];
  85.     static bool inited;
  86.     
  87.     if (!inited) {
  88.         int k;
  89.         inited= TRUE;
  90.         for (k= 0; k <= 15; ++k)
  91.             sines[k]= sin(k * PI/30);
  92.     }
  93.     i= i % 60;
  94.     if (i < 0)
  95.         i += 60;
  96.     if (i <= 15)
  97.         return sines[i];
  98.     if (i <= 30)
  99.         return sines[30-i];
  100.     if (i <= 45)
  101.         return -sines[i-30];
  102.     return -sines[60-i];
  103. }
  104.  
  105. /* Compute the cosine (from the sine) */
  106.  
  107. double
  108. cosine(i)
  109.     int i;
  110. {
  111.     return sine(i+15);
  112. }
  113.  
  114. /* Compute the absolute position of the endpoint of a line drawn at
  115.    i minutes, whose length is a certain percentage of the radius */
  116.  
  117. void
  118. endpoint(i, perc, ph, pv)
  119.     int i;        /* Minutes */
  120.     int perc;    /* Percentage of length */
  121.     int *ph, *pv;    /* Return values */
  122. {
  123.     double s= sine(i), c= cosine(i);
  124.     
  125.     *ph= centh + s*perc*radius/100 + 0.5;
  126.     *pv= centv - c*perc*radius/100 + 0.5;
  127. }
  128.  
  129. /* Draw a mark at i minutes.
  130.    Marks at hour positions are longer, every 3 hours even longer. */
  131.  
  132. void
  133. drawmark(i)
  134.     int i;
  135. {
  136.     int begh, begv;
  137.     int endh, endv;
  138.     int len;
  139.     
  140.     endpoint(i, 100, &endh, &endv);
  141.     if (i % 5 != 0)
  142.         len= 3;
  143.     else if (i % 15 != 0)
  144.         len= 8;
  145.     else
  146.         len= 19;
  147.     endpoint(i, 100-len, &begh, &begv);
  148.     wdrawline(begh, begv, endh, endv);
  149. }
  150.  
  151. /* Draw a hand at i minutes, whose length is a given percentage
  152.    of the radius */
  153.  
  154. void
  155. drawhand(i, perc)
  156.     int i;
  157.     int perc;
  158. {
  159.     int endh, endv;
  160.     endpoint(i, perc, &endh, &endv);
  161.     wdrawline(centh, centv, endh, endv);
  162. }
  163.  
  164. /* Draw a hand in XOR mode */
  165.  
  166. void
  167. xorhand(i, perc)
  168.     int i;
  169.     int perc;
  170. {
  171.     int endh, endv;
  172.     endpoint(i, perc, &endh, &endv);
  173.     wxorline(centh, centv, endh, endv);
  174. }
  175.  
  176. /* Draw the date in the top left corner */
  177.  
  178. void
  179. drawdate(tp)
  180.     struct tm *tp;
  181. {
  182.     char buf[100];
  183.     
  184.     sprintf(buf, "%02d/%02d/%02d", tp->tm_year % 100,
  185.         tp->tm_mon+1, tp->tm_mday);
  186.     werase(0, 0, 10000, centv - radius);
  187.     wdrawtext(0, centv - radius - wlineheight(), buf, -1);
  188. }
  189.  
  190. /* Draw the alarm time in the bottom left corner */
  191.  
  192. void
  193. drawalarm()
  194. {
  195.     char buf[100];
  196.     
  197.     sprintf(buf, "*%02d:%02d", alarm/60, alarm%60);
  198.     wdrawtext(0, centv + radius, buf, -1);
  199. }
  200.  
  201. /* Compute the AM/MP/Noon/Midnight indicator character */
  202.  
  203. int
  204. ampm(tp)
  205.     struct tm *tp;
  206. {
  207.     if (tp->tm_min == 0 && tp->tm_hour%12 == 0) {
  208.         if (tp->tm_hour == 12)
  209.             return 'N';
  210.         else
  211.             return 'M';
  212.     }
  213.     else if (tp->tm_hour < 12)
  214.         return 'A';
  215.     else
  216.         return 'P';
  217. }
  218.  
  219. /* Draw the AM/PM/Noon/Midnight indicator in the top right corner */
  220.  
  221. void
  222. drawampm(c)
  223.     int c;
  224. {
  225.     int dh= wcharwidth('M');
  226.     int dv= wlineheight();
  227.     int h= centh + radius - dh;
  228.     int v= centv - radius - dv;
  229.     
  230.     werase(h, v, h+dh, v+dv);
  231.     wdrawchar(h, v, c);
  232. }
  233.  
  234. #ifdef UGLY
  235.  
  236. /* Draw a shaded square around the clock */
  237.  
  238. #define SHOFF 4
  239.  
  240. void
  241. drawborder()
  242. {
  243.     int d= radius * 10/9;
  244.     int left= centh-d, top= centv-d, right= centh+d, bottom= centv+d;
  245.     wdrawbox(left, top, right, bottom);
  246.     wshade(right, top+4, right+4, bottom+4, 50);
  247.     wshade(left+4, bottom, right, bottom+4, 50);
  248. }
  249.  
  250. /* Draw a shaded circle around the clock's face;
  251.    the shadow is on the top left side, so the face appeares to
  252.    be slightly *lower* than the surrounding material.
  253.    Also a thin vertical line to indicate 6 and 12 o'clock. */
  254.  
  255. void
  256. drawoutline()
  257. {
  258.     wdrawcircle(centh-1, centv-1, radius+2);
  259.     wdrawelarc(centh-1, centv-1, radius+1, radius+1, 45-10, 45+180+10);
  260.     wdrawelarc(centh-1, centv-1, radius  , radius  , 45+10, 45+180-10);
  261.     wdrawline(centh, centv-radius, centh, centv+radius);
  262. }
  263.  
  264. #endif /*UGLY*/
  265.  
  266. /* Compute the little hand position from hour, min */
  267.  
  268. int
  269. littlehand(hour, min)
  270.     int hour, min;
  271. {
  272.     return (hour*5 + (min+6)/12) % 60;
  273. }
  274.  
  275. /* Draw procedure */
  276.  
  277. void
  278. drawproc(win, left, top, right, bottom)
  279.     WINDOW *win;
  280. {
  281.     int i;
  282.     
  283.     /* Draw the fixed elements of the clock */
  284. #ifdef UGLY
  285.     drawborder();
  286.     drawoutline();
  287. #else
  288. #ifdef macintosh
  289.     wdrawcircle(centh+1, centv+1, radius+1);
  290. #else
  291.     wdrawcircle(centh, centv, radius);
  292. #endif
  293.     for (i= 0; i < 12; ++i)
  294.         drawmark(i*5);            /* Hour marks */
  295. #endif
  296.     
  297.     /* Draw the hands */
  298.     drawhand(curtime.tm_min, BIGPERC);
  299.     i= littlehand(curtime.tm_hour, curtime.tm_min);
  300.     if (i != curtime.tm_min)
  301.         xorhand(i, LITPERC);
  302.     if (do_seconds)
  303.         xorhand(curtime.tm_sec, SECPERC);
  304.     
  305.     /* Draw the other elements */
  306.     drawdate(&curtime);
  307.     drawampm(ampm(&curtime));
  308.     if (alarm >= 0)
  309.         drawalarm();
  310.         
  311.     /* Invert if the alarm is going */
  312.     if (excited)
  313.         winvert(0, 0, 10000, 10000);
  314. }
  315.  
  316. /* Compute the nearest clock angle corresponding to
  317.    absolute position (h, v) */
  318.  
  319. int
  320. whereis(h, v)
  321.     int h, v;
  322. {
  323.     double dnew;
  324.     
  325.     h -= centh;
  326.     v -= centv;
  327.     if (h == 0 && v == 0)
  328.         return 0;
  329.     dnew= atan2((double)h, (double)(-v)) * 30.0 / PI;
  330.     if (dnew < 0)
  331.         dnew += 60.0;
  332.     return ((int)(dnew + 0.5)) % 60;
  333. }
  334.  
  335. /* Show a change in time with minimal redrawing */
  336.  
  337. showchange(old, new)
  338.     struct tm *old, *new;
  339. {
  340.     int litold= littlehand(old->tm_hour, old->tm_min);
  341.     int litnew= littlehand(new->tm_hour, new->tm_min);
  342.     int newampm= ampm(new);
  343.     
  344.     wbegindrawing(win);
  345.     
  346.     if (do_seconds && old->tm_sec != new->tm_sec) {
  347.         xorhand(old->tm_sec, SECPERC);
  348.         xorhand(new->tm_sec, SECPERC);
  349.     }
  350.     
  351.     if (old->tm_min != new->tm_min) {
  352.         xorhand(old->tm_min, BIGPERC);
  353.         xorhand(new->tm_min, BIGPERC);
  354.     }
  355.     
  356.     if (litold != litnew ||
  357.         litold == old->tm_min || litnew == new->tm_min) {
  358.         if (litold != old->tm_min)
  359.             xorhand(litold, LITPERC);
  360.         if (litnew != new->tm_min)
  361.             xorhand(litnew, LITPERC);
  362.     }
  363.     
  364.     if (old->tm_mday != new->tm_mday)
  365.         drawdate(new);
  366.     
  367.     if (newampm != ampm(old))
  368.         drawampm(newampm);
  369.     
  370.     wenddrawing(win);
  371.  
  372. }
  373.  
  374. /* Leap year calculation.  Input is year - 1900 (but may be >= 100). */
  375.  
  376. int
  377. isleap(year)
  378.     int year;
  379. {
  380.     year += 1900;
  381.     
  382.     return year%4 == 0 && (year%100 != 0 || year%400 == 0);
  383. }
  384.  
  385. /* Increment a time variable in minutes, and show the change */
  386.  
  387. void
  388. incrshowtime(tp, incr)
  389.     struct tm *tp;
  390.     int incr;
  391. {
  392.     struct tm old;
  393.     static int mdays[12]=
  394.         {31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  395.     
  396.     mdays[1]= 28 + isleap(tp->tm_year);
  397.     
  398.     old= *tp;
  399.     
  400.     tp->tm_min += incr;
  401.     
  402.     while (tp->tm_min >= 60) {
  403.         tp->tm_min -= 60;
  404.         tp->tm_hour++;
  405.         if (tp->tm_hour >= 24) {
  406.             tp->tm_hour -= 24;
  407.             tp->tm_mday++;
  408.             tp->tm_wday= (tp->tm_wday + 1) % 7;
  409.             if (tp->tm_mday > mdays[tp->tm_mon]) {
  410.                 tp->tm_mday= 1;
  411.                 tp->tm_mon++;
  412.                 if (tp->tm_mon >= 12) {
  413.                     tp->tm_mon= 0;
  414.                     tp->tm_year++;
  415.                     mdays[1]= 28 + isleap(tp->tm_year);
  416.                 }
  417.             }
  418.         }
  419.     }
  420.     
  421.     while (tp->tm_min < 0) {
  422.         tp->tm_min += 60;
  423.         tp->tm_hour--;
  424.         if (tp->tm_hour < 0) {
  425.             tp->tm_hour += 24;
  426.             tp->tm_mday--;
  427.             tp->tm_wday= (tp->tm_wday + 6) % 7;
  428.             if (tp->tm_mday < 1) {
  429.                 tp->tm_mon--;
  430.                 if (tp->tm_mon < 0) {
  431.                     tp->tm_mon= 11;
  432.                     tp->tm_year--;
  433.                     mdays[1]= 28 + isleap(tp->tm_year);
  434.                 }
  435.                 tp->tm_mday= mdays[tp->tm_mon];
  436.             }
  437.         }
  438.     }
  439.     
  440.     showchange(&old, tp);
  441. }
  442.  
  443. /* Drag the little hand */
  444.  
  445. void
  446. draglittlehand(h, v)
  447.     int h, v;
  448. {
  449.     EVENT e;
  450.     struct tm newtime;
  451.     int i;
  452.     
  453.     newtime= curtime;
  454.     wsettimer(win, 0);
  455.     
  456.     do {
  457.         wgetevent(&e);
  458.         if (e.type != WE_MOUSE_MOVE && e.type != WE_MOUSE_UP) {
  459.             showchange(&newtime, &curtime);
  460.             wungetevent(&e);
  461.             return;
  462.         }
  463.         i= whereis(e.u.where.h, e.u.where.v) / 5;
  464.         if ((i - newtime.tm_hour) % 12 != 0) {
  465.             int diff= i - newtime.tm_hour;
  466.             while (diff > 6)
  467.                 diff -= 12;
  468.             while (diff < -6)
  469.                 diff += 12;
  470.             incrshowtime(&newtime, diff*60);
  471.         }
  472.     } while (e.type != WE_MOUSE_UP);
  473.     setdatetime(&newtime, FALSE);
  474.     curtime= newtime;
  475. }
  476.  
  477. /* Drag the big hand */
  478.  
  479. void
  480. dragbighand(h, v)
  481.     int h, v;
  482. {
  483.     EVENT e;
  484.     struct tm newtime;
  485.     int i;
  486.     
  487.     newtime= curtime;
  488.     wsettimer(win, 0);
  489.     
  490.     do {
  491.         wgetevent(&e);
  492.         if (e.type != WE_MOUSE_MOVE && e.type != WE_MOUSE_UP) {
  493.             showchange(&newtime, &curtime);
  494.             wungetevent(&e);
  495.             return;
  496.         }
  497.         i= whereis(e.u.where.h, e.u.where.v);
  498.         if (i != newtime.tm_min) {
  499.             int diff= i - newtime.tm_min;
  500.             if (diff > 30)
  501.                 diff -= 60;
  502.             else if (diff < -30)
  503.                 diff += 60;
  504.             incrshowtime(&newtime, diff);
  505.         }
  506.     } while (e.type != WE_MOUSE_UP);
  507.     setdatetime(&newtime, TRUE);
  508.     curtime= newtime;
  509. }
  510.  
  511. /* Test whether the given position lies on the hand at the
  512.    given clock angle with the given length percentage */
  513.  
  514. bool
  515. testhand(h, v, pos, perc)
  516.     int h, v;
  517.     int pos;
  518.     int perc;
  519. {
  520.     long dist2= (h-centh)*(h-centh)+ (v-centv)*(v-centv);
  521.     long length2= ((long)radius*perc/100) * ((long)radius*perc/100);
  522.     
  523.     if (dist2 > length2)
  524.         return FALSE;
  525.     if ((whereis(h, v) - pos) % 60 != 0)
  526.         return FALSE;
  527.     return TRUE;
  528. }
  529.  
  530. /* Recompute the time and the alarm parameters.
  531.    Called every minute, and when other parameters may have changed. */
  532.  
  533. void
  534. newtime(flash)
  535.     bool flash;
  536. {
  537.     struct tm oldtime;
  538.     unsigned long now;
  539.     bool wasalarmed;
  540.     
  541.     /* Save the old time displayed */
  542.     oldtime= curtime;
  543.     
  544.     /* Get the current time */
  545.     time(&now);
  546.     curtime= *localtime(&now);
  547.     
  548.     /* Set the window timer to go off at the next tick */
  549.     if (do_seconds) {
  550.         wsettimer(win, 10);
  551.     }
  552.     else {
  553.         if (curtime.tm_sec >= 59) {
  554.             /* When we wake up just at the end of the minute,
  555.                (which may happen if STDWIN isn't very precise),
  556.                pretend it's a bit later, to avoid waking up
  557.                again in a second */
  558.             curtime.tm_sec -= 60;
  559.             curtime.tm_min += 1;
  560.         }
  561.         wsettimer(win, 10 * (60 - curtime.tm_sec));
  562.     }
  563.     
  564.     /* Check whether the alarm should go off */
  565.     wasalarmed= alarmed;
  566.     if (!wasalarmed)
  567.         okayed= FALSE;
  568.     if (alarm >= 0) {
  569.         int a= alarm;
  570.         int hhmm= curtime.tm_hour*60 + curtime.tm_min;
  571.         if (hhmm < 60 && a >= 23*60)
  572.             hhmm += 24*60; /* Correct for wrap-around */
  573.         alarmed= hhmm >= a && hhmm < a+ALARMTIME;
  574.     }
  575.     else {
  576.         alarmed= okayed= FALSE;
  577.     }
  578.     excited= alarmed && !okayed;
  579.     if (excited) {
  580.         if (!wasalarmed)
  581.             wsetactive(win);
  582.         wfleep();
  583.     }
  584.     if (excited || wasalarmed && !okayed)
  585.         flash= TRUE;
  586.     wmenuenable(mp, OKALARM, excited);
  587.     
  588.     /* Redraw the clock face or schedule a redraw */
  589.     if (flash) {
  590.         changeall();
  591.     }
  592.     else {
  593.         showchange(&oldtime, &curtime);
  594.     }
  595. }
  596.  
  597. /* Time-setting procedure by dragging the hands around */
  598.  
  599. void
  600. changehand(h, v)
  601.     int h, v;
  602. {
  603.     /* Test the little hand first, so that if the hands
  604.        overlap, a click near the center implies the little
  605.        hand and a click further away implies the big hand */
  606.     if (testhand(h, v,
  607.         littlehand(curtime.tm_hour, curtime.tm_min), LITPERC)) {
  608.         /* Drag the little hand -- minutes stay unchanged */
  609.         draglittlehand(h, v);
  610.     }
  611.     else if (testhand(h, v, curtime.tm_min, BIGPERC)) {
  612.         /* Drag the big hand -- hours may change, too */
  613.         dragbighand(h, v);
  614.     }
  615.     else {
  616.         /* No hit -- make some noise */
  617.         wfleep();
  618.     }
  619.     newtime(FALSE);
  620. }
  621.  
  622. /* Recompute the clock size and position
  623.    and the time/alarm information.
  624.    Called initially and when the window is resized. */
  625.  
  626. void
  627. getinfo()
  628. {
  629.     int width, height;
  630.     
  631.     wgetwinsize(win, &width, &height);
  632.     centh= width/2;
  633.     centv= height/2;
  634.     radius= centv - wlineheight();
  635.     CLIPMAX(radius, centh);
  636.     newtime(TRUE);
  637. }
  638.  
  639. /* Set the alarm time from a string formatted as hhmm */
  640.  
  641. bool
  642. setalarm(str)
  643.     char *str;
  644. {
  645.     int al;
  646.     
  647.     if (str[0] == EOS || str[0] == '-' && str[1] == EOS) {
  648.         alarm= -1;
  649.         wmenuenable(mp, CLEARALARM, FALSE);
  650.         return TRUE;
  651.     }
  652.     al= atoi(str);
  653.     if (al < 0 || al > 2400 || al%60 >= 60)
  654.         return FALSE;
  655.     if (al == 2400)
  656.         al= 0;
  657.     alarm= (al/100)*60 + al%100;
  658.     wmenuenable(mp, CLEARALARM, TRUE);
  659.     return TRUE;
  660. }
  661.  
  662. /* Set up the menu */
  663.  
  664. void
  665. buildmenu()
  666. {
  667.     wmenusetdeflocal(TRUE);
  668.     mp= wmenucreate(1, "Klok");
  669.     
  670.     wmenuadditem(mp, "Set alarm...", 'S');
  671.     wmenuadditem(mp, "Clear alarm", 'C');
  672.     wmenuadditem(mp, "OK alarm", 'O');
  673.     wmenuadditem(mp, "", -1);
  674.     wmenuadditem(mp, "Seconds Hand", 'H');
  675.     wmenuadditem(mp, "", -1);
  676.     wmenuadditem(mp, "Quit", 'Q');
  677.     
  678.     wmenuenable(mp, CLEARALARM, alarm >= 0);
  679.     wmenucheck(mp, SECONDSHAND, do_seconds);
  680. }
  681.  
  682. /* Handle a menu selection */
  683.  
  684. void
  685. domenu(item)
  686.     int item;
  687. {
  688.     bool flash= FALSE;
  689.     
  690.     switch (item) {
  691.     case SETALARM: {
  692.         char buf[6];
  693.         if (alarm < 0)
  694.             buf[0]= EOS;
  695.         else
  696.             sprintf(buf, "%02d%02d", alarm/60, alarm%60);
  697.         if (!waskstr("Set alarm:", buf, (int)sizeof buf))
  698.             return;
  699.         if (!setalarm(buf))
  700.             wmessage("Invalid alarm (must be hhmm)");
  701.         okayed= FALSE;
  702.         flash= TRUE;
  703.         break;
  704.         }
  705.     case CLEARALARM:
  706.         if (alarm >= 0) {
  707.             setalarm("");
  708.             flash= TRUE;
  709.         }
  710.         break;
  711.     case OKALARM:
  712.         if (excited) {
  713.             flash= okayed= TRUE;
  714.         }
  715.         break;
  716.     case SECONDSHAND:
  717.         do_seconds= !do_seconds;
  718.         wmenucheck(mp, SECONDSHAND, do_seconds);
  719.         wbegindrawing(win);
  720.         xorhand(curtime.tm_sec, SECPERC);
  721.         wenddrawing(win);
  722.         break;
  723.     case QUIT:
  724.         wclose(win);
  725.         wdone();
  726.         exit(0);
  727.         break;
  728.     }
  729.     newtime(flash);
  730. }
  731.  
  732. #ifndef macintosh
  733. /* Print usage message and exit; called for command line errors */
  734.  
  735. void
  736. usage()
  737. {
  738.     wdone();
  739.     fprintf(stderr, "usage: %s [-s] [-m] [-a hhmm]\n", progname);
  740.     exit(2);
  741. }
  742. #endif
  743.  
  744. /* Main program */
  745.  
  746. main(argc, argv)
  747.     int argc;
  748.     char **argv;
  749. {
  750. #ifdef macintosh
  751.     do_seconds= TRUE;
  752. #endif
  753.     
  754.     /* Initialize */
  755.     winitnew(&argc, &argv);
  756.     buildmenu(); /* Must be done before setalarm is called */
  757.     
  758.     /* Find out program name */
  759.     if (argc > 0) {
  760.         progname= rindex(argv[0], '/');
  761.         if (progname == NULL)
  762.             progname= argv[0];
  763.         else
  764.             ++progname;
  765.     }
  766.     
  767. #ifndef macintosh
  768.     /* Parse command line */
  769.     for (;;) {
  770.         int c= getopt(argc, argv, "msa:");
  771.         if (c == EOF)
  772.             break;
  773.         switch (c) {
  774.         case 's':
  775.             do_seconds= TRUE;
  776.             break;
  777.         case 'm':
  778.             do_seconds= FALSE;
  779.             break;
  780.         case 'a':
  781.             if (!setalarm(optarg))
  782.                 usage();
  783.             break;
  784.         default:
  785.             usage();
  786.             /*NOTREACHED*/
  787.         }
  788.     }
  789.     wmenucheck(mp, SECONDSHAND, do_seconds);
  790. #endif
  791.     
  792.     /* Create the window */
  793.     wsetmaxwinsize(400, 400);
  794.     wsetdefwinsize(120, 120);
  795.     win= wopen("klok", drawproc);
  796.     wmenuattach(win, mp);
  797.     
  798.     /* Main loop */
  799.     getinfo();
  800.     for (;;) {
  801.         EVENT e;
  802.         wgetevent(&e);
  803.         
  804.         switch (e.type) {
  805.         
  806.         case WE_MOUSE_DOWN:
  807.             if (excited)
  808.                 domenu(OKALARM);
  809.             else
  810.                 changehand(e.u.where.h, e.u.where.v);
  811.             break;
  812.         
  813.         case WE_MENU:
  814.             if (e.u.m.id == 1)
  815.                 domenu(e.u.m.item);
  816.             break;
  817.         
  818.         case WE_CHAR:
  819.             if (excited)
  820.                 break;
  821.             switch (e.u.character) {
  822.             case 's':
  823.             case 'S':
  824.                 domenu(SETALARM);
  825.                 break;
  826.             case 'c':
  827.             case 'C':
  828.                 domenu(CLEARALARM);
  829.                 break;
  830.             case 'h':
  831.             case 'H':
  832.                 domenu(SECONDSHAND);
  833.                 break;
  834.             case 'q':
  835.             case 'Q':
  836.                 domenu(QUIT);
  837.                 break;
  838.             }
  839.             break;
  840.         
  841.         case WE_COMMAND:
  842.             switch (e.u.command) {
  843.             case WC_RETURN:
  844.                 newtime(FALSE);
  845.                 break;
  846.             case WC_CLOSE:
  847.             case WC_CANCEL:
  848.                 domenu(QUIT);
  849.                 break;
  850.             }
  851.             break;
  852.         
  853.         case WE_SIZE:
  854.             getinfo();
  855.             break;
  856.         
  857.         case WE_TIMER:
  858.             newtime(FALSE);
  859.             break;
  860.         
  861.         }
  862.     }
  863. }
  864.  
  865. #ifndef atarist
  866. #ifdef unix
  867. #include "bsdsetdate.c"
  868. #endif
  869. #else
  870. setdatetime(tp, minchange)
  871.     struct tm *tp;
  872.     int minchange; /* nonzero if we must reset minutes and seconds, too */
  873. {
  874. /* zzz ... todo */
  875. }
  876. #endif
  877.